/*
 * Copyright (C) Michael Opitz
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA
 */
#ifndef GENERIC_QUEUE_H
#define GENERIC_QUEUE_H

#include "network.h"

#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>

#include <exception>
#include <iostream>
using namespace std;

/** 
 * \brief This namespaces includes all nertwork related stuff.
 * \author Michael Opitz
 */
namespace network {
	template <class T>
	/** 
	 * \brief This class provides a generic synchronized queue.
	 */
	class generic_queue {
	public:
		generic_queue(): _is_interrupt(false) {}
		/** 
		 * \brief put inserts a object in the queue.
		 * 
		 * \param obj is a shared_ptr to the object, you want to insert.
		 */
		void put(boost::shared_ptr<T> obj)
		{
			boost::mutex::scoped_lock l(_monitor);
			_list.push_back(obj);
			_cond.notify_one();
		}
		/** 
		 * \brief get returns a object, you previousely inserted into
		 * the queue. If there are no objects in the queue, your thread
		 * is put into the sleep-state. The returned object is of course
		 * removed from the queue.
		 * 
		 * \return a shared_ptr to a object you previousely inserted is
		 * returned.
		 */
		boost::shared_ptr<T> get()
		{
			boost::mutex::scoped_lock l(_monitor);
			while(_list.empty()) {
				_cond.wait(l);
				if(_is_interrupt) {
					throw std::runtime_error(
						"error, thread should exit");
				}
			}
			boost::shared_ptr<T> tmp(_list.front());
			_list.pop_front();
			return tmp;
		}
		/** 
		 * \brief interrupt wakes all threads up, and throws a
		 * runtime_error-exception to exit all threads.
		 */
		void interrupt()
		{
			boost::mutex::scoped_lock l(_monitor);
			_is_interrupt = true;
			_cond.notify_all();
		}
		/** 
		 * \brief is_interrupt returnes if the queue was interrupted.
		 * 
		 * \return True if the queue was interrupted, false if not.
		 */
		bool is_interrupt() const {
			return _is_interrupt;
		}
	private:
		boost::mutex _monitor;
		boost::condition _cond;
		bool _is_interrupt;
		list<boost::shared_ptr<T> > _list;
	};
}

#endif
